using System;
using System.Collections.Generic;
using System.Windows.Documents;
using YouVisio.Silverlight.TextDiff.Extensions;

namespace YouVisio.Silverlight.TextDiff
{
    public abstract class Difference<T>
    {
        public readonly Operation Operation;
        public readonly T[] Initial;
        public readonly T[] Changed;

        private readonly List<Inline> _initialInlines = new List<Inline>();
        private readonly List<Inline> _changedInlines = new List<Inline>();

        protected Difference(Operation operation, T[] initial, T[] changed)
        {
            if (initial == null && changed == null && operation != Operation.Equal)
            {
                throw new ArgumentException(
                    "The initial and the changes elements in a Defference object cannot be both NULL if operation is: "+operation);
            }
            if (initial != null && changed != null && initial.Length != changed.Length)
            {
                throw new ArgumentException(
                    "The initial and the changes elements in a Defference object are not of same length. Initial={0} Changed={1}"
                    .Args(initial.Length, changed.Length));
            }

            Operation = operation;
            Initial = initial;
            Changed = changed;
        }

        public bool OperationIsModification()
        {
            return Operation == Operation.Insert || Operation == Operation.Delete || Operation == Operation.Change;
        }

        public IEnumerable<KeyValuePair<T, T>> Enumerate()
        {
            var length = Initial == null ? Changed.Length : Initial.Length;
            for(var i = 0; i < length; i++)
            {
                yield return new KeyValuePair<T, T>(
                        Initial == null ? default(T) : Initial[i],
                        Changed == null ? default(T) : Changed[i]
                    );
            }
        }

        public List<Inline> InitialInlines
        {
            get { return this._initialInlines; }
        }
        public List<Inline> ChangedInlines
        {
            get { return this._changedInlines; }
        }
        public Inline AddInitialInline(Inline inline)
        {
            InitialInlines.Add(inline);
            return inline;
        }
        public Inline AddChangedInline(Inline inline)
        {
            ChangedInlines.Add(inline);
            return inline;
        }

    }
}